home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / tc.func.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  33.7 KB  |  1,486 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/tc.func.c,v 3.20 1991/12/19 22:34:14 christos Exp $ */
  2. /*
  3.  * tc.func.c: New tcsh builtins.
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: tc.func.c,v 3.20 1991/12/19 22:34:14 christos Exp $")
  40.  
  41. #include "ed.h"
  42. #include "ed.defns.h"        /* for the function names */
  43. #include "tw.h"
  44. #include "tc.h"
  45.  
  46. #ifdef HESIOD
  47. # include <hesiod.h>
  48. #endif /* HESIOD */
  49.  
  50. extern time_t t_period;
  51. extern int do_logout;
  52. extern int just_signaled;
  53. static bool precmd_active = 0;
  54. static bool periodic_active = 0;
  55. static bool cwdcmd_active = 0;    /* PWP: for cwd_cmd */
  56. static bool beepcmd_active = 0;
  57. static void (*alm_fun)() = NULL;
  58.  
  59. static    void     Reverse    __P((Char *));
  60. static    void     auto_logout    __P((void));
  61. static    char    *xgetpass    __P((char *));
  62. static    void     auto_lock    __P((void));
  63. static    void     insert        __P((struct wordent *, bool));
  64. static    void     insert_we    __P((struct wordent *, struct wordent *));
  65. static    int     inlist        __P((Char *, Char *));
  66.  
  67.  
  68. /*
  69.  * Tops-C shell
  70.  */
  71.  
  72. /*
  73.  * expand_lex: Take the given lex and put an expanded version of it in the
  74.  * string buf. First guy in lex list is ignored; last guy is ^J which we
  75.  * ignore Only take lex'es from position from to position to inclusive Note:
  76.  * csh sometimes sets bit 8 in characters which causes all kinds of problems
  77.  * if we don't mask it here. Note: excl's in lexes have been un-back-slashed
  78.  * and must be re-back-slashed
  79.  * (PWP: NOTE: this returns a pointer to the END of the string expanded
  80.  *             (in other words, where the NUL is).)
  81.  */
  82. /* PWP: this is a combination of the old sprlex() and the expand_lex from
  83.    the magic-space stuff */
  84.  
  85. Char   *
  86. expand_lex(buf, bufsiz, sp0, from, to)
  87.     Char   *buf;
  88.     int     bufsiz;
  89.     struct wordent *sp0;
  90.     int     from, to;
  91. {
  92.     register struct wordent *sp;
  93.     register Char *s, *d, *e;
  94.     register Char prev_c;
  95.     register int i;
  96.  
  97.     buf[0] = '\0';
  98.     prev_c = '\0';
  99.     d = buf;
  100.     e = &buf[bufsiz];        /* for bounds checking */
  101.  
  102.     if (!sp0)
  103.     return (buf);        /* null lex */
  104.     if ((sp = sp0->next) == sp0)
  105.     return (buf);        /* nada */
  106.     if (sp == (sp0 = sp0->prev))
  107.     return (buf);        /* nada */
  108.  
  109.     for (i = 0; i < NCARGS; i++) {
  110.     if ((i >= from) && (i <= to)) {    /* if in range */
  111.         for (s = sp->word; *s && d < e; s++) {
  112.         /*
  113.          * bugfix by Michael Bloom: anything but the current history
  114.          * character {(PWP) and backslash} seem to be dealt with
  115.          * elsewhere.
  116.          */
  117.         if ((*s & QUOTE)
  118.             && (((*s & TRIM) == HIST) ||
  119.             (((*s & TRIM) == '\\') && (prev_c != '\\')))) {
  120.             *d++ = '\\';
  121.         }
  122.         *d++ = (*s & TRIM);
  123.         prev_c = *s;
  124.         }
  125.         if (d < e)
  126.         *d++ = ' ';
  127.     }
  128.     sp = sp->next;
  129.     if (sp == sp0)
  130.         break;
  131.     }
  132.     if (d > buf)
  133.     d--;            /* get rid of trailing space */
  134.  
  135.     return (d);
  136. }
  137.  
  138. Char   *
  139. sprlex(buf, sp0)
  140.     Char   *buf;
  141.     struct wordent *sp0;
  142. {
  143.     Char   *cp;
  144.  
  145.     cp = expand_lex(buf, INBUFSIZE, sp0, 0, NCARGS);
  146.     *cp = '\0';
  147.     return (buf);
  148. }
  149.  
  150. void
  151. Itoa(n, s)            /* convert n to characters in s */
  152.     int     n;
  153.     Char   *s;
  154. {
  155.     int     i, sign;
  156.  
  157.     if ((sign = n) < 0)        /* record sign */
  158.     n = -n;
  159.     i = 0;
  160.     do {
  161.     s[i++] = n % 10 + '0';
  162.     } while ((n /= 10) > 0);
  163.     if (sign < 0)
  164.     s[i++] = '-';
  165.     s[i] = '\0';
  166.     Reverse(s);
  167. }
  168.  
  169. static void
  170. Reverse(s)
  171.     Char   *s;
  172. {
  173.     int     c, i, j;
  174.  
  175.     for (i = 0, j = Strlen(s) - 1; i < j; i++, j--) {
  176.     c = s[i];
  177.     s[i] = s[j];
  178.     s[j] = c;
  179.     }
  180. }
  181.  
  182.  
  183. /*ARGSUSED*/
  184. void
  185. dolist(v, c)
  186.     register Char **v;
  187.     struct command *c;
  188. {
  189.     int     i, k;
  190.     struct stat st;
  191.  
  192.     if (*++v == NULL) {
  193.     (void) t_search(STRNULL, NULL, LIST, 0, 0, 0);
  194.     return;
  195.     }
  196.     gflag = 0;
  197.     tglob(v);
  198.     if (gflag) {
  199.     v = globall(v);
  200.     if (v == 0)
  201.         stderror(ERR_NAME | ERR_NOMATCH);
  202.     }
  203.     else
  204.     v = gargv = saveblk(v);
  205.     trim(v);
  206.     for (k = 0; v[k] != NULL && v[k][0] != '-'; k++);
  207.     if (v[k]) {
  208.     /*
  209.      * We cannot process a flag therefore we let ls do it right.
  210.      */
  211.     static Char STRls[] = {'l', 's', '\0'};
  212.     static Char STRmCF[] = {'-', 'C', 'F', '\0'};
  213.     struct command *t;
  214.     struct wordent cmd, *nextword, *lastword;
  215.     Char   *cp;
  216.  
  217. #ifdef BSDSIGS
  218.     sigmask_t omask = 0;
  219.  
  220.     if (setintr)
  221.         omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
  222. #else /* !BSDSIGS */
  223.     sighold(SIGINT);
  224. #endif /* BSDSIGS */
  225.     if (seterr) {
  226.         xfree((ptr_t) seterr);
  227.         seterr = NULL;
  228.     }
  229.     cmd.word = STRNULL;
  230.     lastword = &cmd;
  231.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  232.     nextword->word = Strsave(STRls);
  233.     lastword->next = nextword;
  234.     nextword->prev = lastword;
  235.     lastword = nextword;
  236.     nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  237.     nextword->word = Strsave(STRmCF);
  238.     lastword->next = nextword;
  239.     nextword->prev = lastword;
  240.     lastword = nextword;
  241.     for (cp = *v; cp; cp = *++v) {
  242.         nextword = (struct wordent *) xcalloc(1, sizeof cmd);
  243.         nextword->word = Strsave(cp);
  244.         lastword->next = nextword;
  245.         nextword->prev = lastword;
  246.         lastword = nextword;
  247.     }
  248.     lastword->next = &cmd;
  249.     cmd.prev = lastword;
  250.  
  251.     /* build a syntax tree for the command. */
  252.     t = syntax(cmd.next, &cmd, 0);
  253.     if (seterr)
  254.         stderror(ERR_OLD);
  255.     /* expand aliases like process() does */
  256.     /* alias(&cmd); */
  257.     /* execute the parse tree. */
  258.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);
  259.     /* done. free the lex list and parse tree. */
  260.     freelex(&cmd), freesyn(t);
  261.     if (setintr)
  262. #ifdef BSDSIGS
  263.         (void) sigsetmask(omask);
  264. #else /* !BSDSIGS */
  265.         (void) sigrelse(SIGINT);
  266. #endif /* BSDSIGS */
  267.     }
  268.     else {
  269.     Char   *dp, *tmp, buf[MAXPATHLEN];
  270.  
  271.     for (k = 0, i = 0; v[k] != NULL; k++) {
  272.         tmp = dnormalize(v[k]);
  273.         dp = &tmp[Strlen(tmp) - 1];
  274.         if (*dp == '/' && dp != tmp)
  275. #ifdef apollo
  276.         if (dp != &tmp[1])
  277. #endif /* apollo */
  278.         *dp = '\0';
  279.         if (stat(short2str(tmp), &st) == -1) {
  280.         if (k != i) {
  281.             if (i != 0)
  282.             xputchar('\n');
  283.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  284.         }
  285.         xprintf("%s: %s.\n", short2str(tmp), strerror(errno));
  286.         i = k + 1;
  287.         }
  288.         else if (S_ISDIR(st.st_mode)) {
  289.         Char   *cp;
  290.  
  291.         if (k != i) {
  292.             if (i != 0)
  293.             xputchar('\n');
  294.             print_by_column(STRNULL, &v[i], k - i, FALSE);
  295.         }
  296.         if (k != 0 && v[1] != NULL)
  297.             xputchar('\n');
  298.         xprintf("%s:\n", short2str(tmp));
  299.         for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE));
  300.         if (dp[-1] != (Char) ('/' | QUOTE))
  301.             *dp++ = '/';
  302.         else 
  303.             dp[-1] &= TRIM;
  304.         *dp = '\0';
  305.         (void) t_search(buf, NULL, LIST, 0, 0, 0);
  306.         i = k + 1;
  307.         }
  308.         xfree((ptr_t) tmp);
  309.     }
  310.     if (k != i) {
  311.         if (i != 0)
  312.         xputchar('\n');
  313.         print_by_column(STRNULL, &v[i], k - i, FALSE);
  314.     }
  315.     }
  316.  
  317.     if (gargv) {
  318.     blkfree(gargv);
  319.     gargv = 0;
  320.     }
  321. }
  322.  
  323. static char *defaulttell = "ALL";
  324. extern bool GotTermCaps;
  325.  
  326. /*ARGSUSED*/
  327. void
  328. dotelltc(v, c)
  329.     register Char **v;
  330.     struct command *c;
  331. {
  332.  
  333.     if (!GotTermCaps)
  334.     GetTermCaps();
  335.  
  336.     TellTC(v[1] ? short2str(v[1]) : defaulttell);
  337. }
  338.  
  339. /*ARGSUSED*/
  340. void
  341. doechotc(v, c)
  342.     register Char **v;
  343.     struct command *c;
  344. {
  345.     if (!GotTermCaps)
  346.     GetTermCaps();
  347.     EchoTC(++v);
  348. }
  349.  
  350. /*ARGSUSED*/
  351. void
  352. dosettc(v, c)
  353.     Char  **v;
  354.     struct command *c;
  355. {
  356.     char    tv[2][BUFSIZE];
  357.  
  358.     if (!GotTermCaps)
  359.     GetTermCaps();
  360.  
  361.     (void) strcpy(tv[0], short2str(v[1]));
  362.     (void) strcpy(tv[1], short2str(v[2]));
  363.     SetTC(tv[0], tv[1]);
  364. }
  365.  
  366. /* The dowhich() is by:
  367.  *  Andreas Luik <luik@isaak.isa.de>
  368.  *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
  369.  *  Azenberstr. 35
  370.  *  D-7000 Stuttgart 1
  371.  *  West-Germany
  372.  * Thanks!!
  373.  */
  374.  
  375. /*ARGSUSED*/
  376. void
  377. dowhich(v, c)
  378.     register Char **v;
  379.     struct command *c;
  380. {
  381.     struct wordent lex[3];
  382.     struct varent *vp;
  383.  
  384.     lex[0].next = &lex[1];
  385.     lex[1].next = &lex[2];
  386.     lex[2].next = &lex[0];
  387.  
  388.     lex[0].prev = &lex[2];
  389.     lex[1].prev = &lex[0];
  390.     lex[2].prev = &lex[1];
  391.  
  392.     lex[0].word = STRNULL;
  393.     lex[2].word = STRret;
  394.  
  395.     while (*++v) {
  396.     if (vp = adrof1(*v, &aliases)) {
  397.         xprintf("%s: \t aliased to ", short2str(*v));
  398.         blkpr(vp->vec);
  399.         xprintf("\n");
  400.     }
  401.     else {
  402.         lex[1].word = *v;
  403.         tellmewhat(lex);
  404.     }
  405.     }
  406. }
  407.  
  408. /* PWP: a hack to start up your stopped editor on a single keystroke */
  409. /* jbs - fixed hack so it worked :-) 3/28/89 */
  410.  
  411. struct process *
  412. find_stop_ed()
  413. {
  414.     register struct process *pp;
  415.     register char *ep, *vp, *cp, *p;
  416.     int     epl, vpl;
  417.  
  418.     if ((ep = getenv("EDITOR")) != NULL) {    /* if we have a value */
  419.     if ((p = strrchr(ep, '/')) != NULL)     /* if it has a path */
  420.         ep = p + 1;        /* then we want only the last part */
  421.     }
  422.     else 
  423.     ep = "ed";
  424.  
  425.     if ((vp = getenv("VISUAL")) != NULL) {    /* if we have a value */
  426.     if ((p = strrchr(vp, '/')) != NULL)     /* and it has a path */
  427.         vp = p + 1;        /* then we want only the last part */
  428.     }
  429.     else 
  430.     vp = "vi";
  431.  
  432.     vpl = strlen(vp);
  433.     epl = strlen(ep);
  434.  
  435.     if (pcurrent == NULL)    /* see if we have any jobs */
  436.     return NULL;        /* nope */
  437.  
  438.     for (pp = proclist.p_next; pp; pp = pp->p_next)
  439.     if (pp->p_procid == pp->p_jobid) {
  440.         p = short2str(pp->p_command);
  441.         /* get the first word */
  442.         for (cp = p; *cp && !isspace(*cp); cp++)
  443.         continue;
  444.         *cp = '\0';
  445.         
  446.         if ((cp = strrchr(p, '/')) != NULL)    /* and it has a path */
  447.         cp = cp + 1;        /* then we want only the last part */
  448.         else
  449.         cp = p;            /* else we get all of it */
  450.  
  451.         /* if we find either in the current name, fg it */
  452.         if (strncmp(ep, cp, (size_t) epl) == 0 ||
  453.         strncmp(vp, cp, (size_t) vpl) == 0)
  454.         return pp;
  455.     }
  456.  
  457.     return NULL;        /* didn't find a job */
  458. }
  459.  
  460. void
  461. fg_proc_entry(pp)
  462.     register struct process *pp;
  463. {
  464. #ifdef BSDSIGS
  465.     sigmask_t omask;
  466. #endif
  467.     jmp_buf osetexit;
  468.     bool    ohaderr;
  469.  
  470.     getexit(osetexit);
  471.  
  472. #ifdef BSDSIGS
  473.     omask = sigblock(sigmask(SIGINT));
  474. #else
  475.     (void) sighold(SIGINT);
  476. #endif
  477.  
  478.     ohaderr = haderr;        /* we need to ignore setting of haderr due to
  479.                  * process getting stopped by a signal */
  480.     if (setexit() == 0) {    /* come back here after pjwait */
  481.     pendjob();
  482.     pstart(pp, 1);        /* found it. */
  483.     pjwait(pp);
  484.     }
  485.  
  486.     resexit(osetexit);
  487.     haderr = ohaderr;
  488.  
  489. #ifdef BSDSIGS
  490.     (void) sigsetmask(omask);
  491. #else /* !BSDSIGS */
  492.     (void) sigrelse(SIGINT);
  493. #endif /* BSDSIGS */
  494.  
  495. }
  496.  
  497. static char *
  498. xgetpass(prm)
  499.     char *prm;
  500. {
  501.     static char pass[9];
  502.     int fd, i;
  503.     sigret_t (*sigint)();
  504.  
  505.     sigint = (sigret_t (*)()) sigset(SIGINT, SIG_IGN);
  506.     Rawmode();    /* Make sure, cause we want echo off */
  507.     if ((fd = open("/dev/tty", O_RDWR)) == -1)
  508.     fd = SHIN;
  509.  
  510.     xprintf("%s", prm); flush();
  511.     for (i = 0;;)  {
  512.     if (read(fd, &pass[i], 1) < 1 || pass[i] == '\n') 
  513.         break;
  514.     if (i < 8)
  515.         i++;
  516.     }
  517.     
  518.     pass[i] = '\0';
  519.  
  520.     if (fd != SHIN)
  521.     (void) close(fd);
  522.     (void) sigset(SIGINT, sigint);
  523.  
  524.     return(pass);
  525. }
  526.     
  527. /*
  528.  * Ask the user for his login password to continue working
  529.  * On systems that have a shadow password, this will only 
  530.  * work for root, but what can we do?
  531.  *
  532.  * If we fail to get the password, then we log the user out
  533.  * immediately
  534.  */
  535. static void
  536. auto_lock()
  537. {
  538.     int i;
  539.     struct passwd *pw;
  540. #ifdef PW_SHADOW
  541.     struct spwd *spw;
  542. #endif /* PW_SHADOW */
  543.     extern char *crypt();
  544.  
  545.  
  546.     /* Get the passwd of our effective user.  */
  547.     if ((pw = getpwuid(geteuid())) == NULL) {
  548.       auto_logout();
  549.       /*NOTREACHED*/
  550.       return;
  551.     }
  552.  
  553. #ifdef PW_SHADOW
  554.     /* Get the shadowed password. */
  555.     if ((spw = getspnam(pw->pw_name)) == NULL) {
  556.       auto_logout();
  557.       /*NOTREACHED*/
  558.       return;
  559.     }
  560. #endif /* PW_SHADOW */
  561.  
  562.     setalarm(0);        /* Not for locking any more */
  563. #ifdef BSDSIGS
  564.     (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)));
  565. #else /* !BSDSIGS */
  566.     (void) sigrelse(SIGALRM);
  567. #endif /* BSDSIGS */
  568.     xprintf("\n"); 
  569.     for (i = 0; i < 5; i++) {
  570.     char *crpp, *pp;
  571.     pp = xgetpass("Password:"); 
  572. #ifdef PW_SHADOW
  573.     crpp = crypt(pp, spw->sp_pwdp);
  574.     if (strcmp(crpp, spw->sp_pwdp) == 0) {
  575. #else /* !PW_SHADOW */
  576.     crpp = crypt(pp, pw->pw_passwd);
  577.     if (strcmp(crpp, pw->pw_passwd) == 0) {
  578. #endif /* PW_SHADOW */
  579.         if (GettingInput && !just_signaled) {
  580.         (void) Rawmode();
  581.         ClearLines();    
  582.         ClearDisp();    
  583.         Refresh();
  584.         }
  585.         just_signaled = 0;
  586.         return;
  587.     }
  588.     xprintf("\nIncorrect passwd for %s\n", pw->pw_name);
  589.     }
  590.     auto_logout();
  591. }
  592.  
  593. static void
  594. auto_logout()
  595. {
  596.     xprintf("auto-logout\n");
  597.     /* Don't leave the tty in raw mode */
  598.     if (editing)
  599.     (void) Cookedmode();
  600.     (void) close(SHIN);
  601.     set(STRlogout, Strsave(STRautomatic));
  602.     child = 1;
  603. #ifdef TESLA
  604.     do_logout = 1;
  605. #endif /* TESLA */
  606.     goodbye(NULL, NULL);
  607. }
  608.  
  609. sigret_t
  610. /*ARGSUSED*/
  611. alrmcatch(snum)
  612. int snum;
  613. {
  614.     time_t  cl, nl;
  615. #ifdef UNRELSIGS
  616.     if (snum)
  617.     (void) sigset(SIGALRM, alrmcatch);
  618. #endif /* UNRELSIGS */
  619.  
  620.     if ((nl = sched_next()) == -1)
  621.     (*alm_fun)();        /* no other possibility - logout */
  622.     (void) time(&cl);
  623.     if (nl <= cl + 1)
  624.     sched_run();
  625.     else
  626.     (*alm_fun)();
  627.     setalarm(1);
  628. #ifndef SIGVOID
  629.     return (snum);
  630. #endif /* !SIGVOID */
  631. }
  632.  
  633. /*
  634.  * Karl Kleinpaste, 21oct1983.
  635.  * Added precmd(), which checks for the alias
  636.  * precmd in aliases.  If it's there, the alias
  637.  * is executed as a command.  This is done
  638.  * after mailchk() and just before print-
  639.  * ing the prompt.  Useful for things like printing
  640.  * one's current directory just before each command.
  641.  */
  642. void
  643. precmd()
  644. {
  645. #ifdef BSDSIGS
  646.     sigmask_t omask;
  647.  
  648.     omask = sigblock(sigmask(SIGINT));
  649. #else /* !BSDSIGS */
  650.     (void) sighold(SIGINT);
  651. #endif /* BSDSIGS */
  652.     if (precmd_active) {    /* an error must have been caught */
  653.     aliasrun(2, STRunalias, STRprecmd);
  654.     xprintf("Faulty alias 'precmd' removed.\n");
  655.     goto leave;
  656.     }
  657.     precmd_active = 1;
  658.     if (!whyles && adrof1(STRprecmd, &aliases))
  659.     aliasrun(1, STRprecmd, NULL);
  660. leave:
  661.     precmd_active = 0;
  662. #ifdef BSDSIGS
  663.     (void) sigsetmask(omask);
  664. #else /* !BSDSIGS */
  665.     (void) sigrelse(SIGINT);
  666. #endif /* BSDSIGS */
  667. }
  668.  
  669. /*
  670.  * Paul Placeway  11/24/87  Added cwd_cmd by hacking precmd() into
  671.  * submission...  Run every time $cwd is set (after it is set).  Useful
  672.  * for putting your machine and cwd (or anything else) in an xterm title
  673.  * space.
  674.  */
  675. void
  676. cwd_cmd()
  677. {
  678. #ifdef BSDSIGS
  679.     sigmask_t omask;
  680.  
  681.     omask = sigblock(sigmask(SIGINT));
  682. #else /* !BSDSIGS */
  683.     (void) sighold(SIGINT);
  684. #endif /* BSDSIGS */
  685.     if (cwdcmd_active) {    /* an error must have been caught */
  686.     aliasrun(2, STRunalias, STRcwdcmd);
  687.     xprintf("Faulty alias 'cwdcmd' removed.\n");
  688.     goto leave;
  689.     }
  690.     cwdcmd_active = 1;
  691.     if (!whyles && adrof1(STRcwdcmd, &aliases))
  692.     aliasrun(1, STRcwdcmd, NULL);
  693. leave:
  694.     cwdcmd_active = 0;
  695. #ifdef BSDSIGS
  696.     (void) sigsetmask(omask);
  697. #else /* !BSDSIGS */
  698.     (void) sigrelse(SIGINT);
  699. #endif /* BSDSIGS */
  700. }
  701.  
  702. /*
  703.  * Joachim Hoenig  07/16/91  Added beep_cmd, run every time tcsh wishes 
  704.  * to beep the terminal bell. Useful for playing nice sounds instead.
  705.  */
  706. void
  707. beep_cmd()
  708. {
  709. #ifdef BSDSIGS
  710.     sigmask_t omask;
  711.  
  712.     omask = sigblock(sigmask(SIGINT));
  713. #else /* !BSDSIGS */
  714.     (void) sighold(SIGINT);
  715. #endif /* BSDSIGS */
  716.     if (beepcmd_active) {    /* an error must have been caught */
  717.     aliasrun(2, STRunalias, STRbeepcmd);
  718.     xprintf("Faulty alias 'beepcmd' removed.\n");
  719.     }
  720.     else {
  721.     beepcmd_active = 1;
  722.     if (!whyles && adrof1(STRbeepcmd, &aliases))
  723.         aliasrun(1, STRbeepcmd, NULL);
  724.     }
  725.     beepcmd_active = 0;
  726. #ifdef BSDSIGS
  727.     (void) sigsetmask(omask);
  728. #else /* !BSDSIGS */
  729.     (void) sigrelse(SIGINT);
  730. #endif /* BSDSIGS */
  731. }
  732.  
  733.  
  734. /*
  735.  * Karl Kleinpaste, 18 Jan 1984.
  736.  * Added period_cmd(), which executes the alias "periodic" every
  737.  * $tperiod minutes.  Useful for occasional checking of msgs and such.
  738.  */
  739. void
  740. period_cmd()
  741. {
  742.     register Char *vp;
  743.     time_t  t, interval;
  744. #ifdef BSDSIGS
  745.     sigmask_t omask;
  746.  
  747.     omask = sigblock(sigmask(SIGINT));
  748. #else /* !BSDSIGS */
  749.     (void) sighold(SIGINT);
  750. #endif /* BSDSIGS */
  751.     if (periodic_active) {    /* an error must have been caught */
  752.     aliasrun(2, STRunalias, STRperiodic);
  753.     xprintf("Faulty alias 'periodic' removed.\n");
  754.     goto leave;
  755.     }
  756.     periodic_active = 1;
  757.     if (!whyles && adrof1(STRperiodic, &aliases)) {
  758.     vp = value(STRtperiod);
  759.     if (vp == NULL)
  760.         return;
  761.     interval = getn(vp);
  762.     (void) time(&t);
  763.     if (t - t_period >= interval * 60) {
  764.         t_period = t;
  765.         aliasrun(1, STRperiodic, NULL);
  766.     }
  767.     }
  768. leave:
  769.     periodic_active = 0;
  770. #ifdef BSDSIGS
  771.     (void) sigsetmask(omask);
  772. #else /* !BSDSIGS */
  773.     (void) sigrelse(SIGINT);
  774. #endif /* BSDSIGS */
  775. }
  776.  
  777. /*
  778.  * Karl Kleinpaste, 21oct1983.
  779.  * Set up a one-word alias command, for use for special things.
  780.  * This code is based on the mainline of process().
  781.  */
  782. void
  783. aliasrun(cnt, s1, s2)
  784.     int     cnt;
  785.     Char   *s1, *s2;
  786. {
  787.     struct wordent w, *new1, *new2;    /* for holding alias name */
  788.     struct command *t = NULL;
  789.     jmp_buf osetexit;
  790.  
  791.     getexit(osetexit);
  792.     if (seterr) {
  793.     xfree((ptr_t) seterr);
  794.     seterr = NULL;    /* don't repeatedly print err msg. */
  795.     }
  796.     w.word = STRNULL;
  797.     new1 = (struct wordent *) xcalloc(1, sizeof w);
  798.     new1->word = Strsave(s1);
  799.     if (cnt == 1) {
  800.     /* build a lex list with one word. */
  801.     w.next = w.prev = new1;
  802.     new1->next = new1->prev = &w;
  803.     }
  804.     else {
  805.     /* build a lex list with two words. */
  806.     new2 = (struct wordent *) xcalloc(1, sizeof w);
  807.     new2->word = Strsave(s2);
  808.     w.next = new2->prev = new1;
  809.     new1->next = w.prev = new2;
  810.     new1->prev = new2->next = &w;
  811.     }
  812.  
  813.     /* expand aliases like process() does. */
  814.     alias(&w);
  815.     /* build a syntax tree for the command. */
  816.     t = syntax(w.next, &w, 0);
  817.     if (seterr)
  818.     stderror(ERR_OLD);
  819.  
  820.     psavejob();
  821.     /* catch any errors here */
  822.     if (setexit() == 0)
  823.     /* execute the parse tree. */
  824.     /*
  825.      * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
  826.      * was execute(t, tpgrp);
  827.      */
  828.     execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);    
  829.     /* done. free the lex list and parse tree. */
  830.     freelex(&w), freesyn(t);
  831.     if (haderr) {
  832.     haderr = 0;
  833.     /*
  834.      * Either precmd, or cwdcmd, or periodic had an error. Call it again so
  835.      * that it is removed
  836.      */
  837.     if (precmd_active)
  838.         precmd();
  839. #ifdef notdef
  840.     /*
  841.      * XXX: On the other hand, just interrupting them causes an error too.
  842.      * So if we hit ^C in the middle of cwdcmd or periodic the alias gets
  843.      * removed. We don't want that. Note that we want to remove precmd
  844.      * though, cause that could lead into an infinite loop. This should be
  845.      * fixed correctly, but then haderr should give us the whole exit
  846.      * status not just true or false.
  847.      */
  848.     else if (cwdcmd_active)
  849.         cwd_cmd();
  850.     else if (beepcmd_active)
  851.         beep_cmd();
  852.     else if (periodic_active)
  853.         period_cmd();
  854. #endif /* notdef */
  855.     }
  856.     /* reset the error catcher to the old place */
  857.     resexit(osetexit);
  858.     prestjob();
  859.     pendjob();
  860. }
  861.  
  862. void
  863. setalarm(lck)
  864.     int lck;
  865. {
  866.     struct varent *vp;
  867.     Char   *cp;
  868.     unsigned alrm_time = 0, lock_time;
  869.     time_t cl, nl, sched_dif;
  870.  
  871.     if (vp = adrof(STRautologout)) {
  872.     if (cp = vp->vec[0]) {
  873.         if ((alrm_time = atoi(short2str(cp)) * 60) > 0)
  874.         alm_fun = auto_logout;
  875.     }
  876.     if ((cp = vp->vec[1])) {
  877.         if ((lock_time = atoi(short2str(cp)) * 60) > 0) {
  878.         if (lck) {
  879.             if (alrm_time == 0 || lock_time < alrm_time) {
  880.             alrm_time = lock_time;
  881.             alm_fun = auto_lock;
  882.             }
  883.         }
  884.         else /* lock_time always < alrm_time */
  885.             if (alrm_time)
  886.             alrm_time -= lock_time;
  887.         }
  888.     }
  889.     }
  890.     if ((nl = sched_next()) != -1) {
  891.     (void) time(&cl);
  892.     sched_dif = nl - cl;
  893.     if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time))
  894.         alrm_time = ((unsigned) sched_dif) + 1;
  895.     }
  896.     (void) alarm(alrm_time);    /* Autologout ON */
  897. }
  898.  
  899. #undef RMDEBUG            /* For now... */
  900.  
  901. void
  902. rmstar(cp)
  903.     struct wordent *cp;
  904. {
  905.     struct wordent *we, *args;
  906.     register struct wordent *tmp, *del;
  907.  
  908. #ifdef RMDEBUG
  909.     static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'};
  910.     Char   *tag;
  911. #endif /* RMDEBUG */
  912.     Char   *charac;
  913.     char    c;
  914.     int     ask, doit, star = 0, silent = 0;
  915.  
  916.     if (!adrof(STRrmstar))
  917.     return;
  918. #ifdef RMDEBUG
  919.     tag = value(STRrmdebug);
  920. #endif /* RMDEBUG */
  921.     we = cp->next;
  922.     while (*we->word == ';' && we != cp)
  923.     we = we->next;
  924.     while (we != cp) {
  925. #ifdef RMDEBUG
  926.     if (*tag)
  927.         xprintf("parsing command line\n");
  928. #endif /* RMDEBUG */
  929.     if (!Strcmp(we->word, STRrm)) {
  930.         args = we->next;
  931.         ask = (*args->word != '-');
  932.         while (*args->word == '-' && !silent) {    /* check options */
  933.         for (charac = (args->word + 1); *charac && !silent; charac++)
  934.             silent = (*charac == 'i' || *charac == 'f');
  935.         args = args->next;
  936.         }
  937.         ask = (ask || (!ask && !silent));
  938.         if (ask) {
  939.         for (; !star && *args->word != ';'
  940.              && args != cp; args = args->next)
  941.             if (!Strcmp(args->word, STRstar))
  942.             star = 1;
  943.         if (ask && star) {
  944.             xprintf("Do you really want to delete all files? [n/y] ");
  945.             flush();
  946.             (void) read(SHIN, &c, 1);
  947.             doit = (c == 'Y' || c == 'y');
  948.             while (c != '\n')
  949.             (void) read(SHIN, &c, 1);
  950.             if (!doit) {
  951.             /* remove the command instead */
  952. #ifdef RMDEBUG
  953.             if (*tag)
  954.                 xprintf("skipping deletion of files!\n");
  955. #endif /* RMDEBUG */
  956.             for (tmp = we;
  957.                  *tmp->word != '\n' &&
  958.                  *tmp->word != ';' && tmp != cp;) {
  959.                 tmp->prev->next = tmp->next;
  960.                 tmp->next->prev = tmp->prev;
  961.                 xfree((ptr_t) tmp->word);
  962.                 del = tmp;
  963.                 tmp = tmp->next;
  964.                 xfree((ptr_t) del);
  965.             }
  966.             if (*tmp->word == ';') {
  967.                 tmp->prev->next = tmp->next;
  968.                 tmp->next->prev = tmp->prev;
  969.                 xfree((ptr_t) tmp->word);
  970.                 del = tmp;
  971.                 xfree((ptr_t) del);
  972.             }
  973.             }
  974.         }
  975.         }
  976.     }
  977.     for (we = we->next;
  978.          *we->word != ';' && we != cp;
  979.          we = we->next);
  980.     if (*we->word == ';')
  981.         we = we->next;
  982.     }
  983. #ifdef RMDEBUG
  984.     if (*tag) {
  985.     xprintf("command line now is:\n");
  986.     for (we = cp->next; we != cp; we = we->next)
  987.         xprintf("%s ", short2str(we->word));
  988.     }
  989. #endif /* RMDEBUG */
  990.     return;
  991. }
  992.  
  993. #ifdef BSDJOBS
  994. /* Check if command is in continue list
  995.    and do a "aliasing" if it exists as a job in background */
  996.  
  997. #undef CNDEBUG            /* For now */
  998. void
  999. continue_jobs(cp)
  1000.     struct wordent *cp;
  1001. {
  1002.     struct wordent *we;
  1003.     register struct process *pp, *np;
  1004.     Char   *cmd, *continue_list, *continue_args_list;
  1005.  
  1006. #ifdef CNDEBUG
  1007.     Char   *tag;
  1008.     static Char STRcndebug[] =
  1009.     {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'};
  1010. #endif /* CNDEBUG */
  1011.     bool    in_cont_list, in_cont_arg_list;
  1012.  
  1013.  
  1014. #ifdef CNDEBUG
  1015.     tag = value(STRcndebug);
  1016. #endif /* CNDEBUG */
  1017.     continue_list = value(STRcontinue);
  1018.     continue_args_list = value(STRcontinue_args);
  1019.     if (*continue_list == '\0' && *continue_args_list == '\0')
  1020.     return;
  1021.  
  1022.     we = cp->next;
  1023.     while (*we->word == ';' && we != cp)
  1024.     we = we->next;
  1025.     while (we != cp) {
  1026. #ifdef CNDEBUG
  1027.     if (*tag)
  1028.         xprintf("parsing command line\n");
  1029. #endif /* CNDEBUG */
  1030.     cmd = we->word;
  1031.     in_cont_list = inlist(continue_list, cmd);
  1032.     in_cont_arg_list = inlist(continue_args_list, cmd);
  1033.     if (in_cont_list || in_cont_arg_list) {
  1034. #ifdef CNDEBUG
  1035.         if (*tag)
  1036.         xprintf("in one of the lists\n");
  1037. #endif /* CNDEBUG */
  1038.         np = NULL;
  1039.         for (pp = proclist.p_next; pp; pp = pp->p_next) {
  1040.         if (prefix(cmd, pp->p_command)) {
  1041.             if (pp->p_index) {
  1042.             np = pp;
  1043.             break;
  1044.             }
  1045.         }
  1046.         }
  1047.         if (np) {
  1048.         insert(we, in_cont_arg_list);
  1049.         }
  1050.     }
  1051.     for (we = we->next;
  1052.          *we->word != ';' && we != cp;
  1053.          we = we->next);
  1054.     if (*we->word == ';')
  1055.         we = we->next;
  1056.     }
  1057. #ifdef CNDEBUG
  1058.     if (*tag) {
  1059.     xprintf("command line now is:\n");
  1060.     for (we = cp->next; we != cp; we = we->next)
  1061.         xprintf("%s ",
  1062.             short2str(we->word));
  1063.     }
  1064. #endif /* CNDEBUG */
  1065.     return;
  1066. }
  1067.  
  1068. /* The actual "aliasing" of for backgrounds() is done here
  1069.    with the aid of insert_we().   */
  1070. static void
  1071. insert(plist, file_args)
  1072.     struct wordent *plist;
  1073.     bool    file_args;
  1074. {
  1075.     struct wordent *now, *last;
  1076.     Char   *cmd, *bcmd, *cp1, *cp2;
  1077.     int     cmd_len;
  1078.     Char   *pause = STRunderpause;
  1079.     int     p_len = Strlen(pause);
  1080.  
  1081.     cmd_len = Strlen(plist->word);
  1082.     cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char)));
  1083.     (void) Strcpy(cmd, plist->word);
  1084. /* Do insertions at beginning, first replace command word */
  1085.  
  1086.     if (file_args) {
  1087.     now = plist;
  1088.     xfree((ptr_t) now->word);
  1089.     now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char)));
  1090.     (void) Strcpy(now->word, STRecho);
  1091.  
  1092.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1093.     now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char)));
  1094.     (void) Strcpy(now->word, STRbackqpwd);
  1095.     insert_we(now, plist);
  1096.  
  1097.     for (last = now; *last->word != '\n' && *last->word != ';';
  1098.          last = last->next);
  1099.  
  1100.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1101.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1102.     (void) Strcpy(now->word, STRgt);
  1103.     insert_we(now, last->prev);
  1104.  
  1105.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1106.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1107.     (void) Strcpy(now->word, STRbang);
  1108.     insert_we(now, last->prev);
  1109.  
  1110.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1111.     now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4);
  1112.     cp1 = now->word;
  1113.     cp2 = cmd;
  1114.     *cp1++ = '~';
  1115.     *cp1++ = '/';
  1116.     *cp1++ = '.';
  1117.     while (*cp1++ = *cp2++);
  1118.     cp1--;
  1119.     cp2 = pause;
  1120.     while (*cp1++ = *cp2++);
  1121.     insert_we(now, last->prev);
  1122.  
  1123.     now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
  1124.     now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
  1125.     (void) Strcpy(now->word, STRsemi);
  1126.     insert_we(now, last->prev);
  1127.     bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char)));
  1128.     cp1 = bcmd;
  1129.     cp2 = cmd;
  1130.     *cp1++ = '%';
  1131.     while (*cp1++ = *cp2++);
  1132.     now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent)));
  1133.     now->word = bcmd;
  1134.     insert_we(now, last->prev);
  1135.     }
  1136.     else {
  1137.     struct wordent *del;
  1138.  
  1139.     now = plist;
  1140.     xfree((ptr_t) now->word);
  1141.     now->word = (Char *) xcalloc(1, 
  1142.                      (size_t) ((cmd_len + 2) * sizeof(Char)));
  1143.     cp1 = now->word;
  1144.     cp2 = cmd;
  1145.     *cp1++ = '%';
  1146.     while (*cp1++ = *cp2++);
  1147.     for (now = now->next;
  1148.          *now->word != '\n' && *now->word != ';' && now != plist;) {
  1149.         now->prev->next = now->next;
  1150.         now->next->prev = now->prev;
  1151.         xfree((ptr_t) now->word);
  1152.         del = now;
  1153.         now = now->next;
  1154.         xfree((ptr_t) del);
  1155.     }
  1156.     }
  1157. }
  1158.  
  1159. static void
  1160. insert_we(new, where)
  1161.     struct wordent *new, *where;
  1162. {
  1163.  
  1164.     new->prev = where;
  1165.     new->next = where->next;
  1166.     where->next = new;
  1167.     new->next->prev = new;
  1168. }
  1169.  
  1170. static int
  1171. inlist(list, name)
  1172.     Char   *list, *name;
  1173. {
  1174.     register Char *l, *n;
  1175.  
  1176.     l = list;
  1177.     n = name;
  1178.  
  1179.     while (*l && *n) {
  1180.     if (*l == *n) {
  1181.         l++;
  1182.         n++;
  1183.         if (*n == '\0' && (*l == ' ' || *l == '\0'))
  1184.         return (1);
  1185.         else
  1186.         continue;
  1187.     }
  1188.     else {
  1189.         while (*l && *l != ' ')
  1190.         l++;        /* skip to blank */
  1191.         while (*l && *l == ' ')
  1192.         l++;        /* and find first nonblank character */
  1193.         n = name;
  1194.     }
  1195.     }
  1196.     return (0);
  1197. }
  1198.  
  1199. #endif /* BSDJOBS */
  1200.  
  1201.  
  1202. /*
  1203.  * Implement a small cache for tilde names. This is used primarily
  1204.  * to expand tilde names to directories, but also
  1205.  * we can find users from their home directories for the tilde
  1206.  * prompt, on machines where yp lookup is slow this can be a big win...
  1207.  * As with any cache this can run out of sync, rehash can sync it again.
  1208.  */
  1209. static struct tildecache {
  1210.     Char   *user;
  1211.     Char   *home;
  1212.     int     hlen;
  1213. }      *tcache = NULL;
  1214.  
  1215. #define TILINCR 10
  1216. int tlength = 0;
  1217. static int tsize = TILINCR;
  1218.  
  1219. static int
  1220. tildecompare(p1, p2)
  1221.     struct tildecache *p1, *p2;
  1222. {
  1223.     return Strcmp(p1->user, p2->user);
  1224. }
  1225.  
  1226. Char   *
  1227. gethomedir(us)
  1228.     Char   *us;
  1229. {
  1230.     register struct passwd *pp;
  1231. #ifdef HESIOD
  1232.     char **res, **res1, *cp;
  1233.     Char *rp;
  1234. #endif /* HESIOD */
  1235.     
  1236.     pp = getpwnam(short2str(us));
  1237. #ifdef YPBUGS
  1238.     fix_yp_bugs();
  1239. #endif /* YPBUGS */
  1240.     if (pp != NULL)
  1241.     return Strsave(str2short(pp->pw_dir));
  1242. #ifdef HESIOD
  1243.     res = hes_resolve(short2str(us), "filsys");
  1244.     rp = 0;
  1245.     if (res != 0) {
  1246.     extern char *strtok();
  1247.     if ((*res) != 0) {
  1248.         /*
  1249.          * Look at the first token to determine how to interpret
  1250.          * the rest of it.
  1251.          * Yes, strtok is evil (it's not thread-safe), but it's also
  1252.          * easy to use.
  1253.          */
  1254.         cp = strtok(*res, " ");
  1255.         if (strcmp(cp, "AFS") == 0) {
  1256.         /* next token is AFS pathname.. */
  1257.         cp = strtok(NULL, " ");
  1258.         if (cp != NULL)
  1259.             rp = Strsave(str2short(cp));
  1260.         } else if (strcmp(cp, "NFS") == 0) {
  1261.         cp = NULL;
  1262.         if ((strtok(NULL, " ")) && /* skip remote pathname */
  1263.             (strtok(NULL, " ")) && /* skip host */
  1264.             (strtok(NULL, " ")) && /* skip mode */
  1265.             (cp = strtok(NULL, " "))) {
  1266.             rp = Strsave(str2short(cp));
  1267.         }
  1268.         }
  1269.     }
  1270.     for (res1 = res; *res1; res1++)
  1271.         free(*res1);
  1272.     return rp;
  1273.     }
  1274. #endif /* HESIOD */
  1275.     return NULL;
  1276. }
  1277.  
  1278. Char   *
  1279. gettilde(us)
  1280.     Char   *us;
  1281. {
  1282.     struct tildecache *bp1, *bp2, *bp;
  1283.     Char *hd;
  1284.  
  1285.     if (tcache == NULL)
  1286.     tcache = (struct tildecache *) xmalloc((size_t) (TILINCR *
  1287.                           sizeof(struct tildecache)));
  1288.     /*
  1289.      * Binary search
  1290.      */
  1291.     for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) {
  1292.     register int i;
  1293.  
  1294.     bp = bp1 + ((bp2 - bp1) >> 1);
  1295.     if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0)
  1296.         return (bp->home);
  1297.     if (i < 0)
  1298.         bp2 = bp;
  1299.     else
  1300.         bp1 = bp + 1;
  1301.     }
  1302.     /*
  1303.      * Not in the cache, try to get it from the passwd file
  1304.      */
  1305.     hd = gethomedir(us);
  1306.     if (hd == NULL)
  1307.     return NULL;
  1308.  
  1309.     /*
  1310.      * Update the cache
  1311.      */
  1312.     tcache[tlength].user = Strsave(us);
  1313.     tcache[tlength].home = hd;
  1314.     tcache[tlength++].hlen = Strlen(hd);
  1315.  
  1316.     (void) qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache),
  1317.          (int (*) __P((const void *, const void *))) tildecompare);
  1318.  
  1319.     if (tlength == tsize) {
  1320.     tsize += TILINCR;
  1321.     tcache = (struct tildecache *) xrealloc((ptr_t) tcache,
  1322.                         (size_t) (tsize *
  1323.                           sizeof(struct tildecache)));
  1324.     }
  1325.     return (hd);
  1326. }
  1327.  
  1328. /*
  1329.  * Return the username if the directory path passed contains a
  1330.  * user's home directory in the tilde cache, otherwise return NULL
  1331.  * hm points to the place where the path became different.
  1332.  * Special case: Our own home directory.
  1333.  * If we are passed a null pointer, then we flush the cache.
  1334.  */
  1335. Char   *
  1336. getusername(hm)
  1337.     Char  **hm;
  1338. {
  1339.     Char   *h, *p;
  1340.     int     i, j;
  1341.  
  1342.     if (hm == NULL) {
  1343.     for (i = 0; i < tlength; i++) {
  1344.         xfree((ptr_t) tcache[i].home);
  1345.         xfree((ptr_t) tcache[i].user);
  1346.     }
  1347.     xfree((ptr_t) tcache);
  1348.     tlength = 0;
  1349.     tsize = TILINCR;
  1350.     tcache = NULL;
  1351.     return NULL;
  1352.     }
  1353.     if (((h = value(STRhome)) != NULL) &&
  1354.     (Strncmp(p = *hm, h, j = Strlen(h)) == 0) &&
  1355.     (p[j] == '/' || p[j] == '\0')) {
  1356.     *hm = &p[j];
  1357.     return STRNULL;
  1358.     }
  1359.     for (i = 0; i < tlength; i++)
  1360.     if ((Strncmp(p = *hm, tcache[i].home, j = tcache[i].hlen) == 0) &&
  1361.         (p[j] == '/' || p[j] == '\0')) {
  1362.         *hm = &p[j];
  1363.         return tcache[i].user;
  1364.     }
  1365.     return NULL;
  1366. }
  1367.  
  1368. /*
  1369.  * PWP: read a bunch of aliases out of a file QUICKLY.  The format
  1370.  *  is almost the same as the result of saying "alias > FILE", except
  1371.  *  that saying "aliases > FILE" does not expand non-letters to printable
  1372.  *  sequences.
  1373.  */
  1374. /*ARGSUSED*/
  1375. void
  1376. doaliases(v, c)
  1377.     Char  **v;
  1378.     struct command *c;
  1379. {
  1380.     jmp_buf oldexit;
  1381.     Char  **vec, *lp;
  1382.     int     fd;
  1383.     Char    buf[BUFSIZE], line[BUFSIZE];
  1384.     char    tbuf[BUFSIZE + 1], *tmp;
  1385.     extern bool output_raw;    /* PWP: in sh.print.c */
  1386.  
  1387.     v++;
  1388.     if (*v == 0) {
  1389.     output_raw = 1;
  1390.     plist(&aliases);
  1391.     output_raw = 0;
  1392.     return;
  1393.     }
  1394.  
  1395.     gflag = 0, tglob(v);
  1396.     if (gflag) {
  1397.     v = globall(v);
  1398.     if (v == 0)
  1399.         stderror(ERR_NAME | ERR_NOMATCH);
  1400.     }
  1401.     else {
  1402.     v = gargv = saveblk(v);
  1403.     trim(v);
  1404.     }
  1405.  
  1406.     if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0)
  1407.     stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno));
  1408.  
  1409.     getexit(oldexit);
  1410.     if (setexit() == 0) {
  1411.     for (;;) {
  1412.         Char   *p = NULL;
  1413.         int     n = 0;
  1414.         lp = line;
  1415.         for (;;) {
  1416.         if (n <= 0) {
  1417.             int     i;
  1418.  
  1419.             if ((n = read(fd, tbuf, BUFSIZE)) <= 0)
  1420.             goto eof;
  1421.             for (i = 0; i < n; i++)
  1422.             buf[i] = tbuf[i];
  1423.             p = buf;
  1424.         }
  1425.         n--;
  1426.         if ((*lp++ = *p++) == '\n') {
  1427.             lp[-1] = '\0';
  1428.             break;
  1429.         }
  1430.         }
  1431.         for (lp = line; *lp; lp++) {
  1432.         if (isspc(*lp)) {
  1433.             *lp++ = '\0';
  1434.             while (isspc(*lp))
  1435.             lp++;
  1436.             vec = (Char **) xmalloc((size_t)
  1437.                         (2 * sizeof(Char **)));
  1438.             vec[0] = Strsave(lp);
  1439.             vec[1] = NULL;
  1440.             setq(strip(line), vec, &aliases);
  1441.             break;
  1442.         }
  1443.         }
  1444.     }
  1445.     }
  1446.  
  1447. eof:
  1448.     (void) close(fd);
  1449.     tw_clear_comm_list();
  1450.     if (gargv)
  1451.     blkfree(gargv), gargv = 0;
  1452.     resexit(oldexit);
  1453. }
  1454.  
  1455.  
  1456. /*
  1457.  * set the shell-level var to 1 or apply change to it.
  1458.  */
  1459. void
  1460. shlvl(val)
  1461.     int val;
  1462. {
  1463.     char *cp;
  1464.  
  1465.     if ((cp = getenv("SHLVL")) != NULL) {
  1466.  
  1467.     val += atoi(cp);
  1468.  
  1469.     if (val <= 0) {
  1470.         unsetv(STRshlvl);
  1471.         Unsetenv(STRSHLVL);
  1472.     }
  1473.     else {
  1474.         Char    buff[BUFSIZE];
  1475.  
  1476.         Itoa(val, buff);
  1477.         set(STRshlvl, Strsave(buff));
  1478.         Setenv(STRSHLVL, buff);
  1479.     }
  1480.     }
  1481.     else {
  1482.     set(STRshlvl, SAVE("1"));
  1483.     Setenv(STRSHLVL, str2short("1"));
  1484.     }
  1485. }
  1486.